package yz.cp.back.admin.controller;


import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import yz.cp.back.admin.vo.SysPermissionEditoVo;
import yz.cp.back.auth.security.SecUser;
import yz.cp.back.auth.security.SecurityUtils;
import yz.cp.back.auth.security.handler.MySecurityMetadataSource;
import yz.cp.back.common.base.BaseController;
import yz.cp.back.common.constant.CommonConstant;
import yz.cp.back.common.res.ApiResult;
import yz.cp.back.common.utils.JacksonUtil;
import yz.cp.back.s.entity.SysPermission;
import yz.cp.back.s.entity.SysRolePermission;
import yz.cp.back.s.entity.SysUser;
import yz.cp.back.s.service.ISysPermissionService;
import yz.cp.back.s.service.ISysRolePermissionService;
import yz.cp.back.s.service.ISysUserService;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;


/**
 * 菜单/权限管理接口
 * @author xukk
 */
@Slf4j
@RestController
@RequestMapping("/web/permission")
@CacheConfig(cacheNames = "permission")
@Transactional
public class PermissionController  extends BaseController {

    @Autowired
    private ISysPermissionService permissionService;

    @Autowired
    private ISysRolePermissionService rolePermissionService;


    @Autowired
    private StringRedisTemplate redisTemplate;


    @Autowired
    private MySecurityMetadataSource mySecurityMetadataSource;

    @Autowired
    private ISysUserService userService;

    /**
     * 获取用户页面菜单数据
     * @return
     */
    @RequestMapping(value = "/getMenuList",method = RequestMethod.GET)
    public ApiResult getAllMenuList(){

        List<SysPermission> list = new ArrayList<>();
        // 读取缓存
        SecUser secUser= SecurityUtils.getSecUser();
        SysUser u=userService.findByUsername(secUser.getUsername());
        String key = "permission::userMenuList:" + u.getId();
        String v = redisTemplate.opsForValue().get(key);
        if(StrUtil.isNotBlank(v)){
            list = JacksonUtil.from(v,new TypeReference<List<SysPermission>>() {});
            return renderOk().add(list);
        }

        // 用户所有权限 已排序去重
        list = permissionService.findByUserId(u.getId());

        List<SysPermission> menuList = new ArrayList<>();
        // 筛选一级页面
        for(SysPermission p : list){
            if(CommonConstant.PERMISSION_PAGE.equals(p.getType())&&CommonConstant.LEVEL_ONE.equals(p.getLevel())){
                menuList.add(p);
            }
        }
        // 筛选二级页面
        List<SysPermission> secondMenuList = new ArrayList<>();
        for(SysPermission p : list){
            if(CommonConstant.PERMISSION_PAGE.equals(p.getType())&&CommonConstant.LEVEL_TWO.equals(p.getLevel())){
                secondMenuList.add(p);
            }
        }
        // 筛选二级页面拥有的按钮权限
        List<SysPermission> buttonPermissions = new ArrayList<>();
        for(SysPermission p : list){
            if(CommonConstant.PERMISSION_OPERATION.equals(p.getType())&&CommonConstant.LEVEL_THREE.equals(p.getLevel())){
                buttonPermissions.add(p);
            }
        }

        // 匹配二级页面拥有权限
        for(SysPermission p : secondMenuList){
            List<String> permTypes = new ArrayList<>();
            for(SysPermission pe : buttonPermissions){
                if(p.getId().equals(pe.getParentId())){
                    permTypes.add(pe.getButtonType());
                }
            }
            p.setPermTypes(permTypes);
        }
        // 匹配一级页面拥有二级页面
        for(SysPermission p : menuList){
            List<SysPermission> secondMenu = new ArrayList<>();
            for(SysPermission pe : secondMenuList){
                if(p.getId().equals(pe.getParentId())){
                    secondMenu.add(pe);
                }
            }
            p.setChildren(secondMenu);
        }

        // 缓存
        redisTemplate.opsForValue().set(key, JacksonUtil.to(menuList));
        return renderOk().add(menuList);
    }

    /**
     * 获取权限菜单树
     * @return
     */
    @RequestMapping(value = "/getAllList",method = RequestMethod.GET)
    @Cacheable(key = "'allList'")
    public ApiResult getAllList(){

        // 一级
        List<SysPermission> list = permissionService.findByLevelOrderBySortOrder(CommonConstant.LEVEL_ONE);
        // 二级
        for(SysPermission p1 : list){
            List<SysPermission> children1 = permissionService.findByParentIdOrderBySortOrder(p1.getId());
            p1.setChildren(children1);
            // 三级
            for(SysPermission p2 : children1){
                List<SysPermission> children2 = permissionService.findByParentIdOrderBySortOrder(p2.getId());
                p2.setChildren(children2);
            }
        }
        return renderOk().add(list);
    }

    /**
     * 添加
     * @param permission
     * @return
     */
    @RequestMapping(value = "/add",method = RequestMethod.POST)
    @CacheEvict(key = "'menuList'")
    public ApiResult add(@ModelAttribute SysPermission permission){

        // 判断拦截请求的操作权限按钮名是否已存在
        if(CommonConstant.PERMISSION_OPERATION.equals(permission.getType())){
            List<SysPermission> list = permissionService.findByTitle(permission.getTitle());
            if(list!=null&&list.size()>0){
                return renderError("名称已存在");
            }
        }
        permissionService.save(permission);
        //重新加载权限
        mySecurityMetadataSource.loadResourceDefine();
        //手动删除缓存
        redisTemplate.delete("permission::allList");
        return renderOk();
    }

    /**
     * 编辑
     * @param vo
     * @return
     */
    @RequestMapping(value = "/edit",method = RequestMethod.POST)
    public ApiResult edit(@ModelAttribute SysPermissionEditoVo vo){
        SysPermission permission=beanMapper.map(vo,SysPermission.class);
        // 判断拦截请求的操作权限按钮名是否已存在
        if(CommonConstant.PERMISSION_OPERATION.equals(permission.getType())){
            // 若名称修改
            SysPermission p = permissionService.getById(permission.getId());
            if(!p.getTitle().equals(permission.getTitle())){
                List<SysPermission> list = permissionService.findByTitle(permission.getTitle());
                if(list!=null&&list.size()>0){
                    return renderError("名称已存在");
                }
            }
        }
        permissionService.updateById(permission);
        //重新加载权限
        mySecurityMetadataSource.loadResourceDefine();
        //手动批量删除缓存
        Set<String> keys = redisTemplate.keys("userPermission:" + "*");
        redisTemplate.delete(keys);
        Set<String> keysUser = redisTemplate.keys("user:" + "*");
        redisTemplate.delete(keysUser);
        Set<String> keysUserMenu = redisTemplate.keys("permission::userMenuList:*");
        redisTemplate.delete(keysUserMenu);
        redisTemplate.delete("permission::allList");
        return renderOk();
    }

    /**
     * 批量通过id删除
     * @param ids
     * @return
     */
    @RequestMapping(value = "/delByIds/{ids}",method = RequestMethod.DELETE)
    @CacheEvict(key = "'menuList'")
    public ApiResult delByIds(@PathVariable String[] ids){

        for(String id:ids){
            List<SysRolePermission> list = rolePermissionService.findByPermissionId(id);
            if(list!=null&&list.size()>0){
                return renderError("删除失败，包含正被角色使用关联的菜单或权限");
            }
        }
        for(String id:ids){
            permissionService.removeById(id);
        }
        //重新加载权限
        mySecurityMetadataSource.loadResourceDefine();
        //手动删除缓存
        redisTemplate.delete("permission::allList");
        return renderOk("批量通过id删除数据成功");
    }

    /**
     * 搜索菜单
     * @param title
     * @return
     */
    @RequestMapping(value = "/search",method = RequestMethod.GET)
    public ApiResult searchPermissionList(@RequestParam String title){

        return  renderOk().add(permissionService.findByTitleLikeOrderBySortOrder(title));
    }
}
